﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web.Configuration;


public class Globals
{
    public static string connectionString = "";
    public const string CS_DISPLAY_DATE_FORMAT = "dd/MM/yyyy";//"dd-MMM-yyyy";
    public const string CS_DISPLAY_TIME_FORMAT = "HH:mm";
    public const string CS_DISPLAY_DATETIME_FORMAT = "dd-MMM-yyyy HH:mm";
    public const string CS_DISPLAY_TIMEDATE_FORMAT = "HH:mm dd-MMM-yyyy";
    public const string CS_DISPLAY_NUMBER_FORMAT = "#,##0";
    public const string CS_EDIT_DATE_FORMAT = "dd/MM/yyyy";
    public const string CS_EDIT_DATETIME_FORMAT = "dd/MM/yyyy HH:mm";
    public const string CS_EDIT_TIME_FORMAT = "HH:mm";
    public const string CS_DECIMAL_SYMBOL = ".";
    public const string CS_DIGIT_GROUP_SYMBOL = ",";
    public const byte CS_DECIMAL_SCALE = 2;
    public const string CS_DATETIME_SYMBOL = "/";
    public const string assemblyTitle = "CDMS";
    public const string assemblyDescription = "Phần mềm quản lý thông tin khách hàng";
    public const string assemblyVersionDate = @"15/12/2016";
    public const string assemblyVersionStr = "1.0.0.0";
    public static int assemblyVersionInt = ToInt32(assemblyVersionStr.Replace(".", ""));
    public static string ProcessorIDs = "";
    
    #region ========= Converter ===============================================================


    public static string Application_GetConfig(string sSectionKey, bool bEncode)
    {
        string sValue = Application_GetConfig(sSectionKey);
        if (bEncode)
        {
            Assembly m_MyAssembly = Assembly.GetCallingAssembly();
            string sGUID = m_MyAssembly.GetType().GUID.ToString();
            sValue = String_Decrypt(sValue, Application_GetID(sGUID));
        }
        return sValue;
    }

    public static string Application_GetConfig(string sSectionKey)
    {
        string sValue = ConfigurationManager.AppSettings[sSectionKey];
        return sValue;
    }

    public static void Application_SetConfig(string sSectionKey, string sValue, bool bEncode)
    {
        if (bEncode)
        {
            Assembly m_MyAssembly = Assembly.GetCallingAssembly();
            string sGUID = m_MyAssembly.GetType().GUID.ToString();
            sValue = String_Encrypt(sValue, Application_GetID(sGUID));
        }
        Application_SetConfig(sSectionKey, sValue);
    }

    public static void Application_SetConfig(string sSectionKey, string sValue)
    {
        System.Configuration.Configuration config = default(System.Configuration.Configuration);
        if (System.Web.HttpRuntime.AppDomainAppId == null)
        {
            config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        }
        else
        {
            config = WebConfigurationManager.OpenWebConfiguration("~");
        }
        // Add an Application Setting.
        if (Array.IndexOf(config.AppSettings.Settings.AllKeys, sSectionKey) >= 0)
        {
            config.AppSettings.Settings[sSectionKey].Value = sValue;
        }
        else
        {
            config.AppSettings.Settings.Add(sSectionKey, sValue);
        }
        // Save the configuration file.
        config.Save(ConfigurationSaveMode.Modified);
        // Force a reload of a changed section.
        ConfigurationManager.RefreshSection("appSettings");
    }

    public static string Application_GetDesc()
    {
        Assembly m_MyAssembly = Assembly.GetEntryAssembly();
        if (m_MyAssembly.IsDefined(typeof(AssemblyDescriptionAttribute), true))
        {
            Attribute attr = Attribute.GetCustomAttribute(m_MyAssembly, typeof(AssemblyDescriptionAttribute));
            AssemblyDescriptionAttribute title_attr = (AssemblyDescriptionAttribute)attr;
            return title_attr.Description;
        }
        else
        {
            return "";
        }
    }

    public static string Application_GetTitle()
    {
        Assembly m_MyAssembly = Assembly.GetEntryAssembly();
        if (m_MyAssembly.IsDefined(typeof(AssemblyTitleAttribute), true))
        {
            Attribute attr = Attribute.GetCustomAttribute(m_MyAssembly, typeof(AssemblyTitleAttribute));
            AssemblyTitleAttribute title_attr = (AssemblyTitleAttribute)attr;
            return title_attr.Title;
        }
        else
        {
            return "";
        }
    }

    public static string Application_GetVersion()
    {
        Assembly m_MyAssembly = Assembly.GetEntryAssembly();
        FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(m_MyAssembly.Location);
        return fvi.FileVersion;
    }

    public static string Application_GetPath()
    {
        Assembly m_MyAssembly = Assembly.GetEntryAssembly();
        string sPath = m_MyAssembly.Location;
        return sPath.Substring(0, sPath.LastIndexOf("\\"));
    }

    private static string Application_GetID(string sGUID)
    {
        //Dim sGUID As String = m_MyAssembly.GetType().GUID.ToString()
        decimal retVal = 0;
        foreach (string sHex in sGUID.Split('-'))
        {
            retVal += long.Parse(sHex, System.Globalization.NumberStyles.HexNumber);
        }
        return retVal.ToString();
    }

    public static string Application_GetID()
    {
        Assembly m_MyAssembly = Assembly.GetEntryAssembly();
        string sGUID = m_MyAssembly.GetType().GUID.ToString();
        return Application_GetID(sGUID);
    }

    public static void Application_SetCultureInfo(System.Threading.Thread mThread)
    {
        //Set khuôn dạng Date và Number cho 1 thread
        System.Globalization.DateTimeFormatInfo myDateformat = new System.Globalization.DateTimeFormatInfo();
        myDateformat.ShortDatePattern = CS_DISPLAY_DATE_FORMAT;
        myDateformat.DateSeparator = CS_DATETIME_SYMBOL;
        myDateformat.FullDateTimePattern = CS_DISPLAY_DATETIME_FORMAT;
        //Set upper case for abb month name
        string[] arrMonthName = myDateformat.AbbreviatedMonthNames;
        arrMonthName.Clone();
        for (int i = 0; i <= arrMonthName.Length - 1; i++)
        {
            arrMonthName[i] = arrMonthName[i].ToUpper();
        }
        myDateformat.AbbreviatedMonthNames = arrMonthName;
        //
        System.Globalization.NumberFormatInfo myNumberformat = new System.Globalization.NumberFormatInfo();
        myNumberformat.NumberDecimalSeparator = CS_DECIMAL_SYMBOL;
        myNumberformat.CurrencyDecimalSeparator = myNumberformat.NumberDecimalSeparator;
        myNumberformat.NumberGroupSeparator = CS_DIGIT_GROUP_SYMBOL;
        myNumberformat.CurrencyGroupSeparator = myNumberformat.NumberGroupSeparator;
        //
        mThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
        mThread.CurrentCulture.DateTimeFormat = myDateformat;
        mThread.CurrentCulture.NumberFormat = myNumberformat;
    }

    public static string TransformCode(string strValue)
    {
        //Chỉ lấy số hoặc chữ trong chuỗi
        return Regex.Replace(strValue.Trim(), @"[^0-9a-zA-Z]", "");
    }

    public static string FormatCurrency(string number)
    {
        string sValue = "";
        if (number != null)
            sValue = String.Format("{0:0,0}", ToDecimal(number));
        return sValue;
    }

    public static String DateTime2StringSQL(Object str)
    {
        //Chỉ áp dụng với trường hợp gán lệnh thực thi sql, hoặc thực thi file excel (do file excel định dạng dấu dựa theo windows)
        return "N'" + ((DateTime)str).ToString("yyyy MMM dd HH:mm:ss") + "'";
    }

    public static String Number2StringSQL(Object number)
    {
        //Đưa đối tượng về chuỗi có dạng "123456.0000"
        //Chỉ áp dụng với trường hợp gán lệnh thực thi sql, hoặc thực thi file excel (do file excel định dạng dấu dựa theo windows)
        NumberFormatInfo numFormat = Thread.CurrentThread.CurrentCulture.NumberFormat;
        String retVal = number.ToString();
        retVal = retVal.Replace(numFormat.NumberGroupSeparator, "@");
        retVal = retVal.Replace(numFormat.NumberDecimalSeparator, ".");
        retVal = retVal.Replace("@", "");
        return retVal;
    }

    public static string GetKeyWord(string KeyWord)
    {
        string _keyword = "";
        if (KeyWord.Contains("'"))
            _keyword = KeyWord.Replace("'", "''");
        else
            _keyword = KeyWord;

        if (_keyword.ToLower().Contains("từ khóa"))
            _keyword = "";

        return _keyword;
    }

    public static string FomatedToVND(string str)
    {
        string cDecimal = Thread.CurrentThread.CurrentUICulture.NumberFormat.CurrencyDecimalSeparator;
        string cGroup = Thread.CurrentThread.CurrentUICulture.NumberFormat.CurrencyGroupSeparator;
        //Đổi dấu chấm dấu @
        str = str.Replace(cDecimal, "@");
        //Được chuỗi bao gồm dấu phẩy(hoặc chấm tùy theo windows) và dấu @
        //Lấy chuỗi vừa đổi rồi lại đổi những chỗ có dấu phẩy(hoặc chấm tùy theo windows) thành dấu chấm
        str = str.Replace(cGroup, ".");
        //Được chuỗi bao gồm dấu chấm và dấu @
        //Lấy chuỗi vừa đổi rồi lại đổi những chỗ có dấu @ thành dấu phẩy
        str = str.Replace("@", ",");
        return str;
    }

    public static Decimal StringVNDToNo(string strVND)
    {
        //strVND có dang: 123.456.789,12
        string str;
        str = strVND.Replace(",", ".");
        str = str.Replace(".", ",");

        Decimal outDec;
        if (Decimal.TryParse(str, out outDec))
            return outDec;
        else
            outDec = 0;
        return outDec;
    }



    public static Boolean ToBoolean(object obj)
    {
        string sValue = "";
        if (obj == null || obj == DBNull.Value)
            sValue = "";
        else
            sValue = obj.ToString();

        Boolean retVal = false;

        if (sValue == "1" || sValue.ToLower() == "true")
            retVal = true;
        else if (!Boolean.TryParse(sValue, out retVal))
            retVal = false;


        return retVal;
    }

    public static String ToString(object obj)
    {
        string sValue = "";
        if (obj == null || obj == DBNull.Value)
            sValue = "";
        else
            sValue = obj.ToString();
        return sValue;
    }

    public static Int32 ToInt32(object obj)
    {
        string sValue = "";
        if (obj == null || obj == DBNull.Value)
            sValue = "";
        else
            sValue = obj.ToString();
        Int32 retVal = 0;

        /*Hàm Int32.TryParse thực hiện dựa theo CurrentCulture của chương trình.
        --> Để có thể sử dụng được tốt việc UISetting từ String sang Int32 
         chỉ cần thay thế ký tự phân cách hàng nghìn thành ký tự trắng. ký tự phân cách thập phân không quan tâm
        */
        //sValue = sValue.Replace(Program.GroupSeparator, "");
        NumberFormatInfo numFormat = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat;
        //
        sValue = sValue.Replace(numFormat.NumberGroupSeparator, "");

        if (!Int32.TryParse(sValue, out retVal))
            retVal = 0;
        return retVal;
    }

    public static Int64 ToInt64(object obj)
    {
        string sValue = "";
        if (obj == null || obj == DBNull.Value)
            sValue = "";
        else
            sValue = obj.ToString();
        Int64 retVal = 0;

        /*Hàm Int32.TryParse thực hiện dựa theo CurrentCulture của chương trình.
        --> Để có thể sử dụng được tốt việc UISetting từ String sang Int32 
         chỉ cần thay thế ký tự phân cách hàng nghìn thành ký tự trắng. ký tự phân cách thập phân không quan tâm
        */
        //sValue = sValue.Replace(Program.GroupSeparator, "");
        NumberFormatInfo numFormat = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat;
        //
        sValue = sValue.Replace(numFormat.NumberGroupSeparator, "");

        if (!Int64.TryParse(sValue, out retVal))
            retVal = 0;
        return retVal;
    }

    public static Decimal ToDecimal(object obj)
    {
        string sValue = "";
        if (obj == null || obj == DBNull.Value)
            sValue = "";
        else
            sValue = obj.ToString();

        Decimal retVal = 0;

        /*Hàm Decimal.TryParse thực hiện dựa theo CurrentCulture của chương trình.
        --> Để có thể sử dụng được tốt việc UISetting từ String sang Decimal 
         chỉ cần thay thế ký tự phân cách hàng nghìn thành ký tự trắng. ký tự phân cách thập phân không quan tâm
        */
        //sValue = sValue.Replace(Program.GroupSeparator, "");
        NumberFormatInfo numFormat = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat;
        //
        sValue = sValue.Replace(numFormat.NumberGroupSeparator, "");

        if (!Decimal.TryParse(sValue, out retVal))
            retVal = 0;
        return retVal;
    }

    public static Double ToDouble(object obj)
    {
        string sValue = "";
        if (obj == null || obj == DBNull.Value)
            sValue = "";
        else
            sValue = obj.ToString();

        Double retVal = 0;

        /*Hàm Decimal.TryParse thực hiện dựa theo CurrentCulture của chương trình.
        --> Để có thể sử dụng được tốt việc UISetting từ String sang Decimal 
         chỉ cần thay thế ký tự phân cách hàng nghìn thành ký tự trắng. ký tự phân cách thập phân không quan tâm
        */
        //sValue = sValue.Replace(Program.GroupSeparator, "");
        NumberFormatInfo numFormat = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat;
        //
        sValue = sValue.Replace(numFormat.NumberGroupSeparator, "");

        if (!Double.TryParse(sValue, out retVal))
            retVal = 0;
        return retVal;
    }

    public static DateTime ToDateTime(object obj)
    {
        string sValue = "";
        if (obj == null || obj == DBNull.Value)
            sValue = "";
        else
            sValue = obj.ToString();

        System.DateTime outDate = DateTime.MinValue;

        if (System.DateTime.TryParseExact(sValue, "dd/MM/yyyy", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AdjustToUniversal, out outDate))
        {
            return outDate;
        }
        else if (System.DateTime.TryParseExact(sValue, "MM/dd/yyyy", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AdjustToUniversal, out outDate))
        {
            return outDate;
        }
        else if (DateTime.TryParseExact(sValue, "d/M/yyyy", null, DateTimeStyles.None, out outDate))
        {
            return outDate;
        }
        else if (DateTime.TryParseExact(sValue, "dd/MM/yy", null, DateTimeStyles.None, out outDate))
        {
            return outDate;
        }
        else if (DateTime.TryParseExact(sValue, "MMM dd yyyy", null, DateTimeStyles.None, out outDate))
        {
            return outDate;
        }
        else if (DateTime.TryParseExact(sValue, "MMM dd yyyy HH:mmtt", null, DateTimeStyles.None, out outDate))
        {
            return outDate;
        }

        else if (DateTime.TryParseExact(sValue, "d-MM-yyyy", null, DateTimeStyles.None, out outDate))
        {
            return outDate;
        }

        else if (DateTime.TryParseExact(sValue, "dd-MM-yyyy", null, DateTimeStyles.None, out outDate))
        {
            return outDate;
        }
        else if (DateTime.TryParseExact(sValue, "d/M/yyyy", null, DateTimeStyles.None, out outDate))
        {
            return outDate;
        }
        else if (DateTime.TryParseExact(sValue, "yyyy'-'MM'-'dd'T'HH':'mm':'ss", null, DateTimeStyles.None, out outDate))
        {
            return outDate;
        }
        else if (System.DateTime.TryParse(sValue, out outDate))
        {
            return outDate;
        }
        else
        {
            return DateTime.MinValue;
        }
    }

    public static string convertToUnSign(string s)
    {
        Regex regex = new Regex("\\p{IsCombiningDiacriticalMarks}+");
        string temp = s.Normalize(NormalizationForm.FormD);
        return regex.Replace(temp, String.Empty).Replace('\u0111', 'd').Replace('\u0110', 'D');
    }

    #endregion =================================================================================

    /// <summary>
    /// Get Description From EnumValue
    /// </summary>
    /// <param name="value"></param>
    /// <returns>var result1 = GetDescriptionFromEnumValue(Animal.GiantPanda);</returns>
    public static string GetDescriptionFromEnumValue(Enum value)
    {
        DescriptionAttribute attribute = value.GetType()
            .GetField(value.ToString())
            .GetCustomAttributes(typeof(DescriptionAttribute), false)
            .SingleOrDefault() as DescriptionAttribute;
        return attribute == null ? value.ToString() : attribute.Description;


    }
    /// <summary>
    /// Get EnumValue From Description
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="description"></param>
    /// <returns>var result2 = GetEnumValueFromDescription<Animal>("Lesser Spotted Anteater");</returns>
    /// 
    public static T GetEnumValueFromDescription<T>(string description)
    {
        var type = typeof(T);
        if (!type.IsEnum)
            throw new ArgumentException();
        FieldInfo[] fields = type.GetFields();
        var field = fields
                        .SelectMany(f => f.GetCustomAttributes(
                            typeof(DescriptionAttribute), false), (
                                f, a) => new { Field = f, Att = a })
                        .Where(a => ((DescriptionAttribute)a.Att)
                            .Description == description).SingleOrDefault();
        return field == null ? default(T) : (T)field.Field.GetRawConstantValue();
    }

    public static string String_Repeat(string sChar, int iCount)
    {
        //Lap lai ky tu n lan
        string sReturn = "";
        if (sChar.Length == 1)
        {
            sReturn = sReturn.PadRight(iCount, sChar[0]);
        }
        else
        {
            for (int i = 1; i <= iCount; i++)
            {
                sReturn += sChar;
            }
        }
        return sReturn;
    }

    public static string String_Encrypt(string strText, string strEncrKey)
    {
        try
        {
            strEncrKey = (strEncrKey + String_Repeat("0", IV.Length)).Substring(0, IV.Length);
            byte[] bykey = System.Text.Encoding.UTF8.GetBytes(strEncrKey);
            byte[] InputByteArray = System.Text.Encoding.UTF8.GetBytes(strText);
            RijndaelManaged des = new RijndaelManaged();
            des.KeySize = IV.Length * 8;
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(bykey, IV), CryptoStreamMode.Write);

            cs.Write(InputByteArray, 0, InputByteArray.Length);
            cs.FlushFinalBlock();

            string retVal = Convert.ToBase64String(ms.ToArray());
            return retVal;
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

    public static byte[] ByteArray_Encrypt(byte[] InputByteArray, string strEncrKey)
    {
        try
        {
            strEncrKey = (strEncrKey + String_Repeat("0", IV.Length)).Substring(0, IV.Length);
            byte[] bykey = System.Text.Encoding.UTF8.GetBytes(strEncrKey);
            RijndaelManaged des = new RijndaelManaged();
            des.KeySize = IV.Length * 8;
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(bykey, IV), CryptoStreamMode.Write);

            cs.Write(InputByteArray, 0, InputByteArray.Length);
            cs.FlushFinalBlock();

            return ms.ToArray();
        }
        catch
        {
            return null;
        }
    }

    private static byte[] IV = { 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0x13, 0x24, 0x57, 0x68, 0x9a, 0xbd, 0xce, 0xdf };

    public static string String_Decrypt(string strText, string sDecrKey)
    {
        byte[] inputByteArray = new byte[strText.Length + 1];
        try
        {
            sDecrKey = (sDecrKey + String_Repeat("0", IV.Length)).Substring(0, IV.Length);
            byte[] byKey = System.Text.Encoding.UTF8.GetBytes(sDecrKey);
            RijndaelManaged des = new RijndaelManaged();
            des.KeySize = IV.Length * 8;
            inputByteArray = Convert.FromBase64String(strText);
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            System.Text.Encoding encoding = System.Text.Encoding.UTF8;

            return encoding.GetString(ms.ToArray());
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }


    public byte[] ByteArray_Decrypt(byte[] inputByteArray, string sDecrKey)
    {
        try
        {
            sDecrKey = (sDecrKey + String_Repeat("0", IV.Length)).Substring(0, IV.Length);
            byte[] byKey = System.Text.Encoding.UTF8.GetBytes(sDecrKey);
            RijndaelManaged des = new RijndaelManaged();
            des.KeySize = IV.Length * 8;
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();

            return ms.ToArray();
        }
        catch
        {
            return null;
        }
    }

    public static bool String_IsAlphaNumeric(string sText)
    {
        //Ham kiem tra chuoi co bao gom ca chu va so hay khong
        //thuong dung de kiem tra khi khoi tao mat khau
        return Regex.IsMatch(sText, "^(?=.*\\d)(?=.*[a-zA-Z])");
    }

    public static string String_StripDiacritics(string sText)
    {
        //Lay chuoi ky tu khong dau
        System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex("\\p{IsCombiningDiacriticalMarks}+");
        //
        string strFormD = sText.Normalize(System.Text.NormalizationForm.FormD);
        return regex.Replace(strFormD, string.Empty).Replace((char)(0x111), 'd').Replace((char)(0x110), 'D').Replace((char)(0xd0), 'D');
    }

    public static string String_ClearInjection(string input)
    {
        if (string.IsNullOrEmpty(input))
        {
            return "";
        }
        else if (input.Contains(";") && (input.Contains("--") || input.Contains("/*") || input.ToUpper().Contains("DECLARE")))
        {
            return "";
        }
        else
        {
            return input.Replace("'", "''");
        }
    }

    public static string String_Number(decimal numValue)
    {
        string sDecChar = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
        string retVal = numValue.ToString();
        retVal = retVal.Replace(sDecChar, ".");
        return retVal;
    }

    public string String_Hash(string input)
    {
        // Create a new instance of the MD5 object.
        System.Security.Cryptography.MD5 md5Hasher = System.Security.Cryptography.MD5.Create();

        // Convert the input string to a byte array and compute the hash.
        byte[] data = md5Hasher.ComputeHash(System.Text.Encoding.Default.GetBytes(input));

        // Create a new Stringbuilder to collect the bytes
        // and create a string.
        System.Text.StringBuilder sBuilder = new System.Text.StringBuilder();

        // Loop through each byte of the hashed data 
        // and format each one as a hexadecimal string.
        int i = 0;
        for (i = 0; i <= data.Length - 1; i++)
        {
            sBuilder.Append(data[i].ToString("x2"));
        }

        // Return the hexadecimal string.
        return sBuilder.ToString();
    }

    public bool String_IsBase64(string sValue)
    {
        return Regex.IsMatch(sValue, "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$");
    }

    public string String_Random(int iLen)
    {
        //Dung cac ky tu chu:
        //   0-9: 48-57 map 0-9
        //   A-Z: 65-90 map 10-35
        //   a-z: 97-122 map 36-61

        string sRet = "";
        string iASCII = "";
        Random r = new Random();

        for (int i = 1; i <= iLen; i++)
        {
            //Lay random 1 so thu tu
            //Chi dung chu hoa nen lay random trong 35
            int iIndex = r.Next(0, 35);
            //Lay ra ascii tuong ung cua ky tu tuong ung voi so thu tu theo map o phan dau
            switch (iIndex)
            {
                case  // ERROR: Case labels with binary operators are unsupported : LessThan
    10:
                    //iIndex = iIndex
                    iIndex += 48;
                    break;
                case  // ERROR: Case labels with binary operators are unsupported : LessThan
    36:
                    iIndex = iIndex + 55;
                    break;
                default:
                    //<62
                    iIndex = iIndex + 61;
                    break;
            }
            //Lay ra ky tu ASCII tuong ung
            sRet += (char)(iIndex);
        }

        r = null;

        return sRet;
    }
    public static string String_Num2Text(string mNumber, bool bUpcaseFirst)
    {
        if (mNumber.Contains(CS_DECIMAL_SYMBOL))
        {
            mNumber = mNumber.Substring(0, mNumber.IndexOf(CS_DECIMAL_SYMBOL));
        }
        mNumber = mNumber.Replace(CS_DIGIT_GROUP_SYMBOL, "");
        //
        int mLen = 0;
        int i = 0;
        int mDigit = 0;
        string mTemp = null;
        string[] mNumText = null;
        mNumText = new string[] { "không", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín" };
        mLen = mNumber.Length;
        for (i = 1; i <= mLen; i++)
        {
            mDigit = int.Parse(mNumber[i - 1].ToString());
            mTemp += " " + mNumText[mDigit];
            if ((mLen == i))
                break; // TODO: might not be correct. Was : Exit For
            decimal tmp = decimal.Remainder(ToDecimal(mLen - i), ToDecimal(9));
            if (tmp == 0m)
            {
                mTemp += " tỷ";
                if (mNumber.Substring(i, 9) == "000000000")
                    i = i + 9;
                if (i >= mLen)
                    break; // TODO: might not be correct. Was : Exit For

                if (mNumber.Substring(i, 3) == "000")
                    i = i + 2;
                //doc ca truong hop "... ty ... khong trieu ... nghin "
                //break;
                //If mNumber.Substring(i, 3) = "000" Then i = i + 3'bo qua truong hop "khong trieu" 
            }
            else if (tmp == 6m)
            {
                mTemp += " triệu";
                if (mNumber.Substring(i, 6) == "000000")
                    i = i + 6;
                if (i >= mLen)
                    break; // TODO: might not be correct. Was : Exit For

                if (mNumber.Substring(i, 3) == "000")
                    i = i + 2;
                //doc ca truong hop "... trieu ... khong nghin ... "
                //break;
                //If mNumber.Substring(i, 3) = "000" Then i = i + 3'bo qua truong hop "khong nghin" 
            }
            else if (tmp == 3m)
            {
                mTemp += " nghìn";
                if (mNumber.Substring(i, 3) == "000")
                    i = i + 3;
                //break;
            }
            else
            {
                decimal defaulttmp = decimal.Remainder((mLen - i), 3);
                if (defaulttmp == 2m)
                    mTemp += " trăm";
                else if (defaulttmp == 1m)
                    mTemp += " mươi";
                //break;
            }
        }
        //bo 00
        mTemp = mTemp.Replace("không mươi không", "");
        //truong hop 0x
        mTemp = mTemp.Replace("không mươi ", "linh ");
        mTemp = mTemp.Replace("mươi không", "mươi");
        mTemp = mTemp.Replace("một mươi", "mười");
        //x4 (x>1)
        mTemp = mTemp.Replace("mươi bốn", "mươi tư");
        //04
        mTemp = mTemp.Replace("linh bốn", "linh tư");
        //x5 (x>1)
        //mTemp = mTemp.Replace("mươi năm", "mươi nhăm")
        mTemp = mTemp.Replace("mươi năm", "mươi lăm");
        //x1 (x>1)
        mTemp = mTemp.Replace("mươi một", "mươi mốt");
        //15
        mTemp = mTemp.Replace("mười năm", "mười lăm");
        //clear double space
        mTemp = mTemp.Replace("  ", " ");
        mTemp = mTemp.Trim();
        if (mTemp.StartsWith("linh "))
            mTemp = mTemp.Substring("linh ".Length);
        if (bUpcaseFirst)
            mTemp = mTemp.Substring(0, 1).ToUpper() + mTemp.Substring(1);
        return mTemp;
    }

    public static string String_Num2Text(string mNumber)
    {
        return String_Num2Text(mNumber, true);
    }
    public string String_Date2Text(DateTime dateValue)
    {
        string retVal = null;
        retVal = "Ngày " + (dateValue.Day <= 10 ? "mùng " : "") + String_Num2Text(dateValue.Day.ToString(), false) + ", tháng " + String_Num2Text(dateValue.Month.ToString(), false) + ", năm " + String_Num2Text(dateValue.Year.ToString(), false);
        return retVal;
    }


    public string String_SqlDate(System.DateTime dtValue)
    {
        if (dtValue.Year > 1900)
        {
            return "CONVERT(DATETIME,'" + dtValue.ToString("dd/MM/yyyy") + "',103)";
        }
        else
        {
            return "";
        }
    }
}

public struct Described<T> where T : struct
{
    private T _value;
    public Described(T value) { _value = value; }

    /// <summary>
    ///  Get the Description attribute of an item.
    /// </summary>
    /// <returns>The string from the Description attribute.</returns>
    public override string ToString()
    {
        try
        {
            string text = _value.ToString();
            object[] attr = typeof(T).GetField(text).GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attr.Length == 1)
            {
                text = ((DescriptionAttribute)attr[0]).Description;
            }
            return text;
        }
        catch
        {
            return "";
        }
    }

    // Implicit helpers to assign between the value and the generic type.
    public static implicit operator Described<T>(T value)
    {
        return new Described<T>(value);
    }
    public static implicit operator T(Described<T> value)
    {
        return value._value;
    }

}

